package com.anuo.app.study.studyjava;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

@RunWith(SpringJUnit4ClassRunner.class)     //表示继承了SpringJUnit4ClassRunner类
@WebAppConfiguration
@ContextConfiguration(locations = {"classpath:spring/spring-context.xml"})

/*
 * Java 反射
 * 研究状态: 常用已完成
 * 应用场景: 运行时获取类或成员信息,调用类方法,动态构造类对象等.
 * 常见操作
 * @获取对象的类型名称
 * @调用某个类的方法；
 * @动态构造某个类的对象；
 * @获取某个字段的值
 * @获取某方法的参数(java 8 特性)
 * 参考:
 *      常见反射操作: http://www.cnblogs.com/lzq198754/p/5780331.html
 *      官方文档: http://docs.oracle.com/javase/tutorial/reflect/index.html 代码示例 看Trail Lessons
 */
public class StudyReflection {

    public static void main(String[] args) {

        getMethodParameter();
        //invokeMethod();
        //instantiateClassObj();
    }

    //获取某个字段的值
    @Test
    public void getFieldValue() {
        //参考文档: http://stackoverflow.com/questions/13400075/reflection-generic-get-field-value
        StudyReflection_Foo obj = new StudyReflection_Foo();
        obj.setName("jk");
        Field field = null;
        try {
            field = obj.getClass().getDeclaredField("name");
            field.setAccessible(true);
            Object value = field.get(obj);
            System.out.println(value);

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }


    }

    //调用某个类的方法
    public static void invokeMethod() {
        StudyReflection_Foo foo = new StudyReflection_Foo();
        Method method;

        try {
            //method=foo.getClass().getMethod("print",new Class<?>[0]);
            //new Class<?>[0] 是什么? 它等同于 null ,  见 http://stackoverflow.com/questions/18117623/meaning-of-new-class0-in-reflection-api
            method = foo.getClass().getMethod("print", String.class, int.class);//如果没有参数就传 null
            method.invoke(foo, "hello", 123);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //动态构造某个类的对象
    public static void instantiateClassObj() {
        Class<?> c = null;
        try {
            c = Class.forName("com.anuo.delib.study.studyjava.StudyReflection_Foo");//加载指定的类
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        StudyReflection_Foo foo = null;
        try {
            foo = (StudyReflection_Foo) c.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        foo.print();

    }

    //获取某方法的参数
    //遗留问题: 获取出的参数名称为 arg0, arg1 要想解决请看下面链接, 在编译java 文件的时候 加-parameter参数
    //参考: https://www.javatpoint.com/java-8-method-parameter-reflection
    public static void getMethodParameter() {
        Calculate calculate = new Calculate();
        Class calculateClass = calculate.getClass();
        Method[] methodInfo = calculateClass.getDeclaredMethods();
        for (Method method : methodInfo) {
            System.out.println(method.getName());//获取方法名
            Parameter[] parameterArray = method.getParameters();
            for (Parameter parameter : parameterArray) {
                System.out.println(parameter.getParameterizedType()); //获取参数类型
                System.out.println(parameter.getName()); //获取参数名字
            }
        }
    }

    //获取对象的类型名称
    public static void getTypeName() {
        StudyReflection_Foo foo = new StudyReflection_Foo();
        System.out.println(foo.getClass().getName());
    }


    private static class Calculate {
        public int add(int a, int b) {
            return a + b;
        }

        public int mul(int a, int b) {
            return a * b;
        }
    }

    private static class StudyReflection_Foo {
        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public void print() {
            System.out.println("hello");
        }

        public void print(String s) {
            System.out.println(s);
        }

        public void print(String s, int d) {
            System.out.println(s + d);
        }
    }
}


